package com.chatplus.application.controller.api;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.chatplus.application.common.constant.RedisPrefix;
import com.chatplus.application.common.domain.response.TurnRightResponse;
import com.chatplus.application.common.exception.BadRequestException;
import com.chatplus.application.common.logging.SouthernQuietLogger;
import com.chatplus.application.common.logging.SouthernQuietLoggerFactory;
import com.chatplus.application.common.util.RedisUtils;
import com.chatplus.application.domain.request.BotCheckCaptchaRequest;
import com.chatplus.application.domain.response.BotCaptchaResponse;
import com.chatplus.application.domain.response.CaptchaResponse;
import com.chatplus.application.web.util.IpUtil;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import com.xingyuv.captcha.util.AESUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.apache.commons.codec.binary.Base64;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Duration;

/**
 * 人机验证
 */
@RestController
@Validated
@RequestMapping("/api/captcha")
public class CaptchaController {
    static final SouthernQuietLogger LOGGER = SouthernQuietLoggerFactory.getLogger(CaptchaController.class);

    private final CaptchaService captchaService;

    private final RedissonClient redissonClient;

    private static final String CAPTCHA_REDIS_KEY = RedisPrefix.TURN_RIGHT_REDIS_PREFIX+"captcha:botCaptcha:";

    @Autowired
    public CaptchaController(CaptchaService captchaService,
                             RedissonClient redissonClient) {
        this.captchaService = captchaService;
        this.redissonClient = redissonClient;
    }

    @GetMapping("/get")
    @SaIgnore
    public BotCaptchaResponse get(HttpServletRequest request) {
        if (request.getRemoteHost() == null) {
            throw new BadRequestException("参数错误");
        }
        CaptchaVO data = new CaptchaVO();
        data.setCaptchaType("clickWord");
        data.setBrowserInfo(IpUtil.getRemoteIp(request));
        ResponseModel responseModel  = captchaService.get(data);
        JSONObject object = JSONUtil.parseObj(responseModel.getRepData());
        BotCaptchaResponse botCaptchaResponse = new BotCaptchaResponse();
        botCaptchaResponse.setKey(object.getStr("token"));
        botCaptchaResponse.setImage("data:image/png;base64,"+object.getStr("originalImageBase64"));
        JSONArray jsonArray = object.getJSONArray("wordList");
        StringBuilder wordList = new StringBuilder();
        for (int i = 0; i < jsonArray.size(); i++) {
            wordList.append(jsonArray.getStr(i));
        }
        redissonClient.getBucket(CAPTCHA_REDIS_KEY+botCaptchaResponse.getKey()).set(object.getStr("secretKey"), Duration.ofMinutes(5));
        botCaptchaResponse.setThumb("data:image/png;base64,"+textToBase64(wordList.toString()));
        return botCaptchaResponse;
    }
    public static String textToBase64(String text){
        try {
            CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 40);
            Image image = captcha.createImage(text);
            // 将字节转换为base64
            return imageToBase64(image);
        } catch (Exception e) {
            LOGGER.message("转换失败").context("text",text).exception(e).error();
        }
        return null;

    }
    public static String imageToBase64(Image image) throws IOException {
        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
        bufferedImage.getGraphics().drawImage(image, 0, 0, null);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "png", outputStream);
        return Base64.encodeBase64String(outputStream.toByteArray());
    }
    @PostMapping("/check")
    @SaIgnore
    public TurnRightResponse check(@RequestBody @Valid BotCheckCaptchaRequest botCheckCaptchaRequest, HttpServletRequest request) throws Exception {
        CaptchaVO data = new CaptchaVO();
        data.setCaptchaType("clickWord");
        data.setToken(botCheckCaptchaRequest.getKey());
        RBucket<String> rBucket = redissonClient.getBucket(CAPTCHA_REDIS_KEY+botCheckCaptchaRequest.getKey());
        String secretKey = rBucket.isExists()?rBucket.get():null;
        JSONArray jsonArray = getObjects(botCheckCaptchaRequest, secretKey);
        data.setPointJson(AESUtil.aesEncrypt(jsonArray.toString(),secretKey));
        data.setBrowserInfo(IpUtil.getRemoteIp(request));
        ResponseModel responseModel  = captchaService.check(data);
        boolean success = responseModel.isSuccess();
        if (!success) {
            throw  new BadRequestException(responseModel.getRepMsg());
        }
        redissonClient.getBucket(CAPTCHA_REDIS_KEY+botCheckCaptchaRequest.getKey()).set(Boolean.TRUE, Duration.ofMinutes(1));
        return new TurnRightResponse(0,"success",null);
    }

    @NotNull
    private static JSONArray getObjects(BotCheckCaptchaRequest botCheckCaptchaRequest, String secretKey) {
        if (secretKey == null){
            throw  new BadRequestException("验证码过期，请重新获取");
        }
        String[] coordinates = botCheckCaptchaRequest.getDots().split(",");
        JSONArray jsonArray = new JSONArray();
        for (int i = 0; i < coordinates.length; i += 2) {
            int x = Integer.parseInt(coordinates[i]);
            int y = Integer.parseInt(coordinates[i + 1]);
            JSONObject object = new JSONObject();
            object.set("x",x);
            object.set("y",y);
            jsonArray.add(object);
        }
        return jsonArray;
    }

    /**
     * 生成验证码
     */
    @GetMapping("/code")
    @SaIgnore
    public CaptchaResponse getCode() {
        CaptchaResponse captchaResponse = new CaptchaResponse();
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = RedisPrefix.USER_LOGIN_PREFIX + uuid;
        // 生成验证码
        CodeGenerator codeGenerator = ReflectUtil.newInstance(RandomGenerator.class, 4);
        // 圆圈干扰
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
        captcha.setGenerator(codeGenerator);
        captcha.createCode();
        String code = captcha.getCode();
        RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(2));
        captchaResponse.setUuid(uuid);
        captchaResponse.setImg(captcha.getImageBase64());
        return captchaResponse;
    }
}
